#ifndef cder_CTaylor_h_included
#define cder_CTaylor_h_included
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_MAP_SIZE 90
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50
#define BOOST_MPL_LIMIT_SET_SIZE 50

#include <assert.h>
#include <cmath>
#include <utility>
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
#include <type_traits>
#include <boost/mpl/size.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/long.hpp>
#include <boost/mpl/accumulate.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/min_max.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/less_equal.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/mpl/greater.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/back.hpp>
#include <boost/mpl/pop_back.hpp>
#include <boost/mpl/times.hpp>

#include <boost/lambda/lambda.hpp>
//#include <boost/lambda/numeric.hpp>
#include <boost/lambda/if.hpp>
#include <boost/lambda/bind.hpp> 
#include <map>
#include "compile_time_expression.h"
#include "finite.h"

//#include <boost/mpl/range.hpp>


namespace std
{
// adds two values
template<typename T>
struct self
{	typedef T type;
};
template<typename SUM, typename VALUE>
struct add
{	typedef boost::mpl::long_<SUM::value + VALUE::value> type;
};
// adds two values
template<typename SUM>
struct add<SUM, boost::mpl::void_>
{	typedef SUM type;
};
// adds two values
template<typename SUM>
struct add<boost::mpl::void_, SUM>
{	typedef SUM type;
};
// sums all values inside a vector
template<typename VECTOR>
struct sum
{	typedef typename boost::mpl::accumulate<
		VECTOR,
		boost::mpl::long_<0>,
		add<boost::mpl::_1, boost::mpl::_2>
	>::type type;
};
// inserts a pair of pos and item into  map
template<typename MAP, typename ITEM>
struct insertPos2Item
{	typedef typename boost::mpl::insert<
		MAP,
		boost::mpl::pair<
			typename boost::mpl::size<MAP>::type,
			ITEM
		>
	>::type type;
};
// creates a map of pos 2 item from a vector
template<typename VECTOR>
struct createPos2Order
{	typedef typename boost::mpl::accumulate<
		VECTOR,
		boost::mpl::map<>,
		insertPos2Item<boost::mpl::_1, boost::mpl::_2>
	>::type type;
};
// inserts item 2 pos into a map
template<typename MAP, typename ITEM>
struct insertItem2Pos
{	typedef typename boost::mpl::insert<
		MAP,
		boost::mpl::pair<
			ITEM,
			typename boost::mpl::size<MAP>::type
		>
	>::type type;
};
// creates a map of item 2 pos from a vector
template<typename VECTOR>
struct createOrder2Pos
{	typedef typename boost::mpl::accumulate<
		VECTOR,
		boost::mpl::map<>,
		insertItem2Pos<boost::mpl::_1, boost::mpl::_2>
	>::type type;
};


// creates type resulting from multiplication of two cders
template<typename T0, typename T1>
struct createTypeMultiplication;
template<typename T0, typename T1>
struct createTypeAdditionSubtraction;


template<typename T0>
struct createTypeNonlinear;


// creates type matching integer power
template<typename T0, typename T1>
struct createTypePow
{	typedef typename boost::mpl::accumulate<
		typename boost::mpl::range_c<
			std::size_t,
			1,
			T1::value
		>::type,
		T0,
		createTypeMultiplication<boost::mpl::_1, T0>
	>::type type;
};


// looks if the vector has zero sum (means indicates value)
// and returns the position
template<typename OLD, typename PAIR>
struct checkForZeroSum
{	typedef typename boost::mpl::if_<
		typename boost::mpl::equal_to<
			typename sum<
				typename PAIR::second
			>::type,
			boost::mpl::long_<0>
		>::type,
		typename PAIR::first,
		OLD
	>::type type;
};
// finds the position of the value (zero order)
template<typename POS2ORDER>
struct findValuePos
{	typedef typename boost::mpl::accumulate<
		POS2ORDER,
		boost::mpl::void_,
		checkForZeroSum<boost::mpl::_1, boost::mpl::_2>
	>::type type;
};
template<typename V0, typename V1>
struct addEnum2Order;


template<typename ORDER>
struct createSingleVariableCTaylor;


template<typename SET, typename VECTOR, typename MAXORDER>
struct filterEnum2Order
{	typedef typename boost::mpl::if_<
		typename boost::mpl::greater<
			typename sum<VECTOR>::type,
			MAXORDER
		>::type,
		self<SET>,
		boost::mpl::push_back<
			SET,
			VECTOR
		>
	>::type::type type;
};
template<typename SET, typename MAXORDER>
struct filterEnum2OrderSet
{	typedef typename boost::mpl::accumulate<
		SET,
		boost::mpl::vector<>,
		filterEnum2Order<boost::mpl::_1, boost::mpl::_2, MAXORDER>
	>::type type;
};


template<typename VECTOR>
struct checkLastVectorElement
{	typedef typename boost::mpl::not_equal_to<
		typename boost::mpl::back<VECTOR>::type,
		boost::mpl::long_<0>
	>::type type;
};
template<typename STATE, typename VECTOR>
struct checkVectorElement
{	typedef typename boost::mpl::and_<
		STATE,
		typename boost::mpl::if_<
			typename boost::mpl::equal_to<
				typename boost::mpl::size<VECTOR>::type,
				boost::mpl::long_<0>
			>::type,
			self<boost::mpl::bool_<true> >,
			checkLastVectorElement<VECTOR>
		>::type::type
	>::type type;
};
template<typename VECTOR>
struct checkNoTrailingZeros
{	typedef typename boost::mpl::accumulate<
		VECTOR,
		boost::mpl::bool_<true>,
		checkVectorElement<boost::mpl::_1, boost::mpl::_2>
	>::type type;
};
// _POS2ENUM2ORDER is a vector of vectors. 
// The inner vector contains order matching the enumeration used for index.
// _MAXORDER is max. order
//template<typename _POS2ENUM2ORDER, typename _MAXORDER>
template<typename _PAIR>
struct CTaylor
{	BOOST_MPL_ASSERT((typename boost::mpl::is_sequence<typename _PAIR::first>::type));
	BOOST_MPL_ASSERT((typename checkNoTrailingZeros<typename _PAIR::first>::type));
	typedef typename _PAIR::first POS2ENUM2ORDER;
	typedef typename _PAIR::second MAXORDER;
	static const std::size_t SIZE = boost::mpl::size<POS2ENUM2ORDER>::type::value;
	typedef typename createPos2Order<POS2ENUM2ORDER>::type POS2ORDER;
	typedef typename createOrder2Pos<POS2ENUM2ORDER>::type ORDER2POS;
	BOOST_MPL_ASSERT((typename boost::mpl::is_sequence<ORDER2POS>::type));
	typedef typename findValuePos<POS2ORDER>::type VALUEPOS;
	double m_ad[SIZE];

	void check(void) const
	{	for (std::size_t i = 0; i < SIZE; ++i)
			assert(foelsche::finite(m_ad[i]));
	}
	__forceinline CTaylor(void)
	{
	}
	__forceinline CTaylor(const double _d, std::size_t)
	{	BOOST_MPL_ASSERT(
			(typename boost::mpl::equal_to<
				typename boost::mpl::size<POS2ENUM2ORDER>::type,
				boost::mpl::long_<2>
			>::type)
		);
		m_ad[VALUEPOS::value] = _d;
		m_ad[1 - VALUEPOS::value] = 1.0;
		check();
	}
	__forceinline CTaylor(const double _d)
	{	//std::fill(m_ad, m_ad + VALUEPOS::value, 0.0);
		for (std::size_t i = 0; i < VALUEPOS::value; ++i)
			m_ad[i] = 0;
		m_ad[VALUEPOS::value] = _d;
		//std::fill(m_ad + VALUEPOS::value + 1, m_ad + SIZE, 0.0);
		for (std::size_t i = VALUEPOS::value + 1; i < SIZE; ++i)
			m_ad[i] = 0;
		check();
	}
	template<typename POS2ENUM2ORDER_1>
	struct copy
	{	CTaylor *const m_pTarget;
		typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > SOURCE;
		const SOURCE &m_rSource;
		__forceinline copy(
			CTaylor *const _pTarget,
			const SOURCE &_rSource)
			:m_pTarget(_pTarget),
			m_rSource(_rSource)
		{
		}
		template<typename TARGET_ORDER>
		__forceinline void operator()(const TARGET_ORDER&_r) const
		{	(*this)(typename boost::mpl::at<ORDER2POS, TARGET_ORDER>::type(), typename boost::mpl::at<typename SOURCE::ORDER2POS, TARGET_ORDER>::type());
		}
		template<typename TARGET_POS>
		__forceinline void operator()(const TARGET_POS&, const boost::mpl::void_&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = 0.0;
		}
		template<typename TARGET_POS, typename SOURCE_POS>
		__forceinline void operator()(const TARGET_POS&, const SOURCE_POS&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = m_rSource.m_ad[SOURCE_POS::value];
		}
	};
	template<typename _BOOL, typename ENUM2ORDER>
	struct check_enum2order
	{	typedef typename boost::mpl::and_<
			typename boost::mpl::has_key<ORDER2POS, ENUM2ORDER>::type,
			_BOOL
		>::type type;
	};
	template<typename POS2ENUM2ORDER_1>
	struct check_pos2enum2order
	{	typedef typename boost::mpl::accumulate<
			POS2ENUM2ORDER_1,
			boost::mpl::bool_<true>,
			check_enum2order<boost::mpl::_1, boost::mpl::_2>
		>::type type;
	};
	__forceinline CTaylor(const CTaylor &_r)
	{	//std::copy(_r.m_ad, _r.m_ad + SIZE, m_ad);
		for (std::size_t i = 0; i < SIZE; ++i)
			m_ad[i] = _r.m_ad[i];
		check();
	}
	__forceinline CTaylor&operator=(const CTaylor&_r)
	{	if (&_r != this)
			for (std::size_t i = 0; i < SIZE; ++i)
				m_ad[i] = _r.m_ad[i];
		check();
		return *this;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline CTaylor(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r)
	{	BOOST_MPL_ASSERT((typename check_pos2enum2order<POS2ENUM2ORDER_1>::type));
		boost::mpl::for_each<POS2ENUM2ORDER>(copy<POS2ENUM2ORDER_1>(this, _r));
		check();
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline CTaylor &operator=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r)
	{	BOOST_MPL_ASSERT((typename check_pos2enum2order<POS2ENUM2ORDER_1>::type));
		boost::mpl::for_each<POS2ENUM2ORDER>(copy<POS2ENUM2ORDER_1>(this, _r));
		check();
		return *this;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline CTaylor &operator+=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r)
	{	*this = *this + _r;
		check();
		return *this;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline CTaylor &operator-=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r)
	{	*this = *this - _r;
		check();
		return *this;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline CTaylor &operator/=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r)
	{	*this = *this / _r;
		check();
		return *this;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline CTaylor &operator*=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r)
	{	*this = *this * _r;
		check();
		return *this;
	}
	template<typename POS2ENUM2ORDER_1>
	struct add
	{	typedef typename createTypeAdditionSubtraction<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET *const m_pTarget;
		typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > SOURCE;
		const SOURCE &m_r1;
		const CTaylor &m_r0;
		__forceinline add(
			CRET *const _pTarget,
			const CTaylor &_r0,
			const SOURCE &_r1)
			:m_pTarget(_pTarget),
			m_r1(_r1),
			m_r0(_r0)
		{
		}
		template<typename TARGET_ORDER>
		__forceinline void operator()(const TARGET_ORDER&_r) const
		{	(*this)(
				typename boost::mpl::at<typename CRET::ORDER2POS, TARGET_ORDER>::type(), 
				typename boost::mpl::at<ORDER2POS, TARGET_ORDER>::type(),
				typename boost::mpl::at<typename SOURCE::ORDER2POS, TARGET_ORDER>::type()
			);
		}
		template<typename TARGET_POS, typename RPOS>
		__forceinline void operator()(const TARGET_POS&, const boost::mpl::void_&, const RPOS&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = m_r1.m_ad[RPOS::value];
		}
		template<typename TARGET_POS, typename LPOS>
		__forceinline void operator()(const TARGET_POS&, const LPOS&, const boost::mpl::void_&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = m_r0.m_ad[LPOS::value];
		}
		template<typename TARGET_POS, typename LPOS, typename RPOS>
		__forceinline void operator()(const TARGET_POS&, const LPOS&, const RPOS&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = m_r0.m_ad[LPOS::value] + m_r1.m_ad[RPOS::value];
		}
	};
	template<typename POS2ENUM2ORDER_1>
	__forceinline typename createTypeAdditionSubtraction<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type operator+(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	typedef typename createTypeAdditionSubtraction<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET s;
		boost::mpl::for_each<typename CRET::POS2ENUM2ORDER>(add<POS2ENUM2ORDER_1>(&s, *this, _r));
		s.check();
		return s;
	}
	__forceinline CTaylor operator+(const double _d) const
	{	CTaylor s;
		//std::copy(m_ad, m_ad + SIZE, s.m_ad);
		for (std::size_t i = 0; i < SIZE; ++i)
			s.m_ad[i] = m_ad[i];
		s.m_ad[VALUEPOS::value] += _d;
		s.check();
		return s;
	}
	__forceinline friend CTaylor operator+(const double _d, const CTaylor &_r)
	{	CTaylor s;
		//std::copy(_r.m_ad, _r.m_ad + SIZE, s.m_ad);
		for (std::size_t i = 0; i < SIZE; ++i)
			s.m_ad[i] = _r.m_ad[i];
		s.m_ad[VALUEPOS::value] += _d;
		s.check();
		return s;
	}
	template<typename POS2ENUM2ORDER_1>
	struct sub
	{	typedef typename createTypeAdditionSubtraction<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET *const m_pTarget;
		typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > SOURCE;
		const SOURCE &m_r1;
		const CTaylor &m_r0;
		__forceinline sub(
			CRET *const _pTarget,
			const CTaylor &_r0,
			const SOURCE &_r1)
			:m_pTarget(_pTarget),
			m_r1(_r1),
			m_r0(_r0)
		{
		}
		template<typename TARGET_ORDER>
		__forceinline void operator()(const TARGET_ORDER&_r) const
		{	(*this)(
				typename boost::mpl::at<typename CRET::ORDER2POS, TARGET_ORDER>::type(), 
				typename boost::mpl::at<ORDER2POS, TARGET_ORDER>::type(),
				typename boost::mpl::at<typename SOURCE::ORDER2POS, TARGET_ORDER>::type()
			);
		}
		template<typename TARGET_POS, typename RPOS>
		__forceinline void operator()(const TARGET_POS&, const boost::mpl::void_&, const RPOS&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = -m_r1.m_ad[RPOS::value];
		}
		template<typename TARGET_POS, typename LPOS>
		__forceinline void operator()(const TARGET_POS&, const LPOS&, const boost::mpl::void_&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = m_r0.m_ad[LPOS::value];
		}
		template<typename TARGET_POS, typename LPOS, typename RPOS>
		__forceinline void operator()(const TARGET_POS&, const LPOS&, const RPOS&) const
		{	m_pTarget->m_ad[TARGET_POS::value] = m_r0.m_ad[LPOS::value] - m_r1.m_ad[RPOS::value];
		}
	};
	template<typename POS2ENUM2ORDER_1>
	__forceinline typename createTypeAdditionSubtraction<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type operator-(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	typedef typename createTypeAdditionSubtraction<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET s;
		boost::mpl::for_each<typename CRET::POS2ENUM2ORDER>(sub<POS2ENUM2ORDER_1>(&s, *this, _r));
		s.check();
		return s;
	}
	__forceinline CTaylor operator-(const double _d) const
	{	CTaylor s;
		//std::copy(m_ad, m_ad + SIZE, s.m_ad);
		for (std::size_t i = 0; i < SIZE; ++i)
			s.m_ad[i] = m_ad[i];
		s.m_ad[VALUEPOS::value] -= _d;
		s.check();
		return s;
	}
	__forceinline friend CTaylor operator-(const double _d, const CTaylor &_r)
	{	CTaylor s;
		for (std::size_t i = 0; i < SIZE; ++i)
			s.m_ad[i] = -_r.m_ad[i];
		s.m_ad[VALUEPOS::value] += _d;
		s.check();
		return s;
	}
	template<typename POS2ENUM2ORDER_1, typename LEFT_ORDER>
	struct mult_sub
	{	typedef typename createTypeMultiplication<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET *const m_pTarget;
		typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > SOURCE;
		const SOURCE &m_r1;
		const CTaylor &m_r0;
		__forceinline mult_sub(
			CRET *const _pTarget,
			const CTaylor &_r0,
			const SOURCE &_r1)
			:m_pTarget(_pTarget),
			m_r1(_r1),
			m_r0(_r0)
		{
		}
		template<typename RIGHT_ORDER>
		__forceinline void operator()(const RIGHT_ORDER&) const
		{	typedef typename addEnum2Order<LEFT_ORDER, RIGHT_ORDER>::type ADD;
			typedef typename sum<ADD>::type SUM;
			typedef typename boost::mpl::less_equal<SUM, MAXORDER>::type LESS_EQUAL;
			(*this)(RIGHT_ORDER(), LESS_EQUAL()); 
		}
		template<typename RIGHT_ORDER>
		__forceinline void operator()(const RIGHT_ORDER&, const boost::mpl::bool_<true>&) const
		{	typedef typename addEnum2Order<LEFT_ORDER, RIGHT_ORDER>::type ADD;
			//typedef typename sum<ADD>::type SUM;
			typedef typename boost::mpl::at<
				typename CRET::ORDER2POS,
				ADD
			>::type TARGET_POS;
			typedef typename boost::mpl::at<
				ORDER2POS,
				LEFT_ORDER
			>::type LEFT_POS;
			typedef typename boost::mpl::at<
				typename SOURCE::ORDER2POS,
				RIGHT_ORDER
			>::type RIGHT_POS;
			m_pTarget->m_ad[TARGET_POS::value] += m_r0.m_ad[LEFT_POS::value]*m_r1.m_ad[RIGHT_POS::value];
		}
		template<typename RIGHT_ORDER>
		__forceinline void operator()(const RIGHT_ORDER&, const boost::mpl::bool_<false>&) const
		{
		}
	};
	template<typename POS2ENUM2ORDER_1>
	struct mult
	{	typedef typename createTypeMultiplication<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET *const m_pTarget;
		typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > SOURCE;
		const SOURCE &m_r1;
		const CTaylor &m_r0;
		__forceinline mult(
			CRET *const _pTarget,
			const CTaylor &_r0,
			const SOURCE &_r1)
			:m_pTarget(_pTarget),
			m_r1(_r1),
			m_r0(_r0)
		{
		}
		template<typename LEFT_ORDER>
		__forceinline void operator()(const LEFT_ORDER&_r) const
		{	typedef typename sum<LEFT_ORDER>::type SUM;
			boost::mpl::for_each<typename filterEnum2OrderSet<POS2ENUM2ORDER_1, boost::mpl::long_<MAXORDER::value - SUM::value> >::type>(mult_sub<POS2ENUM2ORDER_1, LEFT_ORDER>(m_pTarget, m_r0, m_r1));
		}
	};
	template<typename POS2ENUM2ORDER_1>
	__forceinline typename createTypeMultiplication<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type operator*(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	typedef typename createTypeMultiplication<CTaylor, CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > >::type CRET;
		CRET s(0.0);
		boost::mpl::for_each<POS2ENUM2ORDER>(mult<POS2ENUM2ORDER_1>(&s, *this, _r));
		s.check();
		return s;
	}
	__forceinline friend CTaylor operator*(const double _d, const CTaylor &_r)
	{	CTaylor s;
		for (std::size_t i = 0; i < SIZE; i++)
			s.m_ad[i] = _r.m_ad[i]*_d;
		s.check();
		return s;
	}
	__forceinline CTaylor operator*(const double _d) const
	{	CTaylor s;
		for (std::size_t i = 0; i < SIZE; ++i)
			s.m_ad[i] = m_ad[i]*_d;
		s.check();
		return s;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline typename createTypeMultiplication<
		CTaylor, 
		typename createTypeNonlinear<
			CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >
		>::type
	>::type operator/(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return *this*(1.0/_r);
	}
	CTaylor operator/(const double _d) const
	{	assert(_d != 0.0);
		CTaylor s;
		for (std::size_t i = 0; i < SIZE; i++)
			s.m_ad[i] = m_ad[i]/_d;
		s.check();
		return s;
	}
	struct div
	{	typedef typename createSingleVariableCTaylor<MAXORDER>::type CRET;
		CRET *const m_p;
		__forceinline div(CRET *const _p)
			:m_p(_p)
		{
		}
		//template<>
		__forceinline void operator()(const boost::mpl::integral_c<std::size_t, 1>&) const
		{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type POS;
			typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<> >::type PREVPOS;
			m_p->m_ad[POS::value] = 
				-m_p->m_ad[PREVPOS::value]
				*m_p->m_ad[CRET::VALUEPOS::value];
		}
		template<typename T>
		__forceinline void operator()(const T&) const
		{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value> > >::type POS;
			typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value - 1> > >::type PREVPOS;
			m_p->m_ad[POS::value] = 
				-m_p->m_ad[PREVPOS::value]
				*m_p->m_ad[CRET::VALUEPOS::value];
		}
	};
	__forceinline friend typename createTypeNonlinear<
		CTaylor
	>::type operator/(const double _d, const CTaylor &_r)
	{	typedef typename createSingleVariableCTaylor<MAXORDER>::type CRET;
		CRET s;
		s.m_ad[CRET::VALUEPOS::value] = _d/_r.m_ad[VALUEPOS::value];
		boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 1, CRET::SIZE>::type>(div(&s));
/*
		for (std::size_t i = 1; i < CRET::SIZE; i++)
			s.m_ad[i] = - s.m_ad[i-1]*s.m_ad[0];
*/
		return s.apply(_r - _r.m_ad[VALUEPOS::value]);
	}
	__forceinline CTaylor operator-(void) const
	{	CTaylor s;
		for (std::size_t i = 0; i < SIZE; ++i)
			s.m_ad[i] = -m_ad[i];
		s.check();
		return s;
	}
/*
	friend CTaylor ddx(const CTaylor &_r)
	{	CTaylor s;
		for (std::size_t i = 1; i < SIZE; ++i)
			s.m_ad[i - 1] = i*m_ad[i];
		s.m_ad[SIZE-1] = 0.0;
		s.check();
		return s;
	}
*/
	template<std::size_t I, std::size_t IMAX, typename POS2ENUM2ORDER_1>
	struct calculateApply;

	template<std::size_t IMAX, typename POS2ENUM2ORDER_1>
	struct calculateApply<0, IMAX, POS2ENUM2ORDER_1>
	{	typedef typename createTypeMultiplication<
			CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >,
			typename calculateApply<1, IMAX, POS2ENUM2ORDER_1>::RET
		>::type RET;
		__forceinline RET operator()(const CTaylor &_rThis, const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
		{	typedef typename boost::mpl::at<ORDER2POS, boost::mpl::vector<> >::type AT;
			return _rThis.m_ad[AT::value] + _r*calculateApply<1, IMAX, POS2ENUM2ORDER_1>()(_rThis, _r);
		}
	};
	template<std::size_t IMAX, typename POS2ENUM2ORDER_1>
	struct calculateApply<IMAX, IMAX, POS2ENUM2ORDER_1>
	{	typedef double RET;
		__forceinline double operator()(const CTaylor &_rThis, const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
		{	typedef typename boost::mpl::at<ORDER2POS, boost::mpl::vector<boost::mpl::long_<IMAX> > >::type AT;
			return _rThis.m_ad[AT::value];
		}
	};
	template<std::size_t I, std::size_t IMAX, typename POS2ENUM2ORDER_1>
	struct calculateApply
	{	typedef typename createTypeMultiplication<
			CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >,
			typename calculateApply<I+1, IMAX, POS2ENUM2ORDER_1>::RET
		>::type RET;
		__forceinline RET operator()(const CTaylor &_rThis, const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
		{	typedef typename boost::mpl::at<ORDER2POS, boost::mpl::vector<boost::mpl::long_<I> > >::type AT;
			return _rThis.m_ad[AT::value] + _r*calculateApply<I+1, IMAX, POS2ENUM2ORDER_1>()(_rThis, _r);
		}
	};
	template<typename POS2ENUM2ORDER_1>
	__forceinline typename calculateApply<0, SIZE-1, POS2ENUM2ORDER_1>::RET apply(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return calculateApply<0, SIZE-1, POS2ENUM2ORDER_1>()(*this, _r);
	}
	struct print
	{	const CTaylor &m_r;
		std::ostream &m_s;
		__forceinline print(
			const CTaylor &_r,
			std::ostream &_s
		)
			:m_r(_r),
			m_s(_s)
		{
		}
		template<typename ORDER>
		__forceinline void operator()(const ORDER &)const
		{	boost::mpl::for_each<ORDER>(*this);
			typedef typename boost::mpl::at<ORDER2POS, ORDER>::type POS;
			m_s << " = " << m_r.m_ad[POS::value] << ", ";
		}
		template<unsigned long I>
		__forceinline void operator()(const boost::mpl::long_<I> &) const
		{	m_s << I << ":";
		}
	};
	__forceinline friend std::ostream &operator<<(std::ostream &_rS, const CTaylor &_r)
	{	boost::mpl::for_each<POS2ENUM2ORDER>(print(_r, _rS));
		return _rS;
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline bool operator<(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return m_ad[VALUEPOS::value] < _r.m_ad[CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >::VALUEPOS::value];
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline bool operator>(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return m_ad[VALUEPOS::value] > _r.m_ad[CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >::VALUEPOS::value];
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline bool operator<=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return m_ad[VALUEPOS::value] <= _r.m_ad[CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >::VALUEPOS::value];
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline bool operator>=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return m_ad[VALUEPOS::value] >= _r.m_ad[CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >::VALUEPOS::value];
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline bool operator==(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return m_ad[VALUEPOS::value] == _r.m_ad[CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >::VALUEPOS::value];
	}
	template<typename POS2ENUM2ORDER_1>
	__forceinline bool operator!=(const CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> > &_r) const
	{	return m_ad[VALUEPOS::value] != _r.m_ad[CTaylor<boost::mpl::pair<POS2ENUM2ORDER_1, MAXORDER> >::VALUEPOS::value];
	}


	__forceinline friend bool operator<(const double _d, const CTaylor &_r)
	{	return _d < _r.m_ad[VALUEPOS::value];
	}
	__forceinline friend bool operator>(const double _d, const CTaylor &_r)
	{	return _d > _r.m_ad[VALUEPOS::value];
	}
	__forceinline friend bool operator<=(const double _d, const CTaylor &_r)
	{	return _d <= _r.m_ad[VALUEPOS::value];
	}
	__forceinline friend bool operator>=(const double _d, const CTaylor &_r)
	{	return _d >= _r.m_ad[VALUEPOS::value];
	}
	__forceinline friend bool operator==(const double _d, const CTaylor &_r)
	{	return _d == _r.m_ad[VALUEPOS::value];
	}
	__forceinline friend bool operator!=(const double _d, const CTaylor &_r)
	{	return _d != _r.m_ad[VALUEPOS::value];
	}


	__forceinline bool operator<(const double _r) const
	{	return m_ad[VALUEPOS::value] < _r;
	}
	__forceinline bool operator>(const double _r) const
	{	return m_ad[VALUEPOS::value] > _r;
	}
	__forceinline bool operator<=(const double _r) const
	{	return m_ad[VALUEPOS::value] <= _r;
	}
	__forceinline bool operator>=(const double _r) const
	{	return m_ad[VALUEPOS::value] >= _r;
	}
	__forceinline bool operator==(const double _r) const
	{	return m_ad[VALUEPOS::value] == _r;
	}
	__forceinline bool operator!=(const double _r) const
	{	return m_ad[VALUEPOS::value] != _r;
	}

	template<typename V>
	__forceinline double get(const V&) const
	{	typedef typename boost::mpl::at<ORDER2POS, V>::type POS;
		BOOST_MPL_ASSERT_NOT((typename std::is_same<POS, boost::mpl::void_>::type));
		return getByPos(POS());
	}
	template<typename POS>
	__forceinline double getByPos(const POS&) const
	{	return m_ad[POS::value];
	}
/*
	__forceinline double getByPos(const boost::mpl::void_&) const
	{	return 0;
	}
*/
};

template<typename TARGET, typename ORDER>
struct pushBackOrder
{	typedef typename boost::mpl::push_back<
		TARGET,
		boost::mpl::vector<boost::mpl::long_<ORDER::value+1> >
	>::type type;
};
template<typename ORDER>
struct createSingleVariableCTaylor
{	typedef typename boost::mpl::accumulate<
		typename boost::mpl::range_c<
			std::size_t,
			0,
			ORDER::value
		>::type,
		boost::mpl::vector<
			boost::mpl::vector<>
		>,
		pushBackOrder<boost::mpl::_1, boost::mpl::_2>
	>::type POS2ENUM2ORDER;
	typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER, ORDER> > type;
};

template<typename T0, typename T1>
struct createTypeMultiplication;


template<typename _POS2ENUM2ORDER0, typename _POS2ENUM2ORDER1, typename _MAXORDER>
struct createTypeAdditionSubtraction<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER0, _MAXORDER> >, CTaylor<boost::mpl::pair<_POS2ENUM2ORDER1, _MAXORDER> > >
{	typedef typename boost::mpl::accumulate<
		_POS2ENUM2ORDER0,
		boost::mpl::set<>,
		boost::mpl::insert<boost::mpl::_1, boost::mpl::_2>
	>::type SET0;
	typedef typename boost::mpl::accumulate<
		_POS2ENUM2ORDER1,
		SET0,
		boost::mpl::insert<boost::mpl::_1, boost::mpl::_2>
	>::type SET1;
#if 1
	typedef typename boost::mpl::accumulate<
		SET1,
		boost::mpl::vector<>,
		boost::mpl::push_back<boost::mpl::_1, boost::mpl::_2>
	>::type VECTOR;
	typedef CTaylor<boost::mpl::pair<VECTOR, _MAXORDER> > type;
#else
	typedef CTaylor<boost::mpl::pair<SET1, _MAXORDER> > type;
#endif
};


template<typename _POS2ENUM2ORDER, typename _MAXORDER>
struct createTypeAdditionSubtraction<double, CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >
{	typedef CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > type;
}; 


template<typename _POS2ENUM2ORDER, typename _MAXORDER>
struct createTypeAdditionSubtraction<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >, double>
{	typedef CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > type;
}; 

template<>
struct createTypeAdditionSubtraction<double, double>
{	typedef double type;
}; 


template<typename A, typename B, typename C, typename D>
struct createTypeAdditionSubtraction<std::pair<A, B>, std::pair<C, D> >
{	typedef std::pair<
		typename createTypeAdditionSubtraction<A, C>::type,
		typename createTypeAdditionSubtraction<B, D>::type
	> type;
};


template<typename OUTPUT, typename POS, typename V0, typename V1>
struct addEntriesFromVector
{	typedef typename boost::mpl::if_<
		typename boost::mpl::greater<
			typename boost::mpl::size<V0>::type,
			POS
		>::type,
		boost::mpl::at<V0, POS>,
		boost::mpl::long_<0>
	>::type::type VALUE0;
	typedef typename boost::mpl::if_<
		typename boost::mpl::greater<
			typename boost::mpl::size<V1>::type,
			POS
		>::type,
		boost::mpl::at<V1, POS>,
		boost::mpl::long_<0>
	>::type::type VALUE1;
	typedef typename boost::mpl::push_back<
		OUTPUT,
		typename add<
			VALUE0,
			VALUE1
		>::type
	>::type type;	
};
template<typename V0, typename V1>
struct addEnum2Order
{	typedef typename boost::mpl::accumulate<
		typename boost::mpl::range_c<
			std::size_t, 
			0,
			boost::mpl::max<
				typename boost::mpl::size<V0>::type,
				typename boost::mpl::size<V1>::type
			>::type::value
		>::type,
		boost::mpl::vector<>,
		addEntriesFromVector<boost::mpl::_1, boost::mpl::_2, V0, V1>
	>::type type;
};
template<typename VECTOR, typename INDEX, typename ENUM2ORDER0, typename ENUM2ORDER1>
struct findAndMultiplyAndPushBack
{	typedef typename boost::mpl::if_<
		typename boost::mpl::greater<
			typename boost::mpl::size<ENUM2ORDER0>::type,
			INDEX
		>::type,
		boost::mpl::at<
			ENUM2ORDER0,
			INDEX
		>,
		boost::mpl::long_<0>
	>::type::type VALUE0;
	typedef typename boost::mpl::if_<
		typename boost::mpl::greater<
			typename boost::mpl::size<ENUM2ORDER1>::type,
			INDEX
		>::type,
		boost::mpl::at<
			ENUM2ORDER1,
			INDEX
		>,
		boost::mpl::long_<0>
	>::type::type VALUE1;
	typedef typename boost::mpl::push_back<
		VECTOR,
		typename add<VALUE0, VALUE1>::type
	>::type type;
};
template<typename SET, typename ENUM2ORDER0, typename ENUM2ORDER1, typename MAXORDER>
struct multiplyOrder2
{	typedef typename boost::mpl::max<
		typename boost::mpl::size<ENUM2ORDER0>::type,
		typename boost::mpl::size<ENUM2ORDER1>::type
	>::type SIZE;
	typedef typename boost::mpl::accumulate<
		typename boost::mpl::range_c<std::size_t, 0, SIZE::value>::type,
		boost::mpl::vector<>,
		findAndMultiplyAndPushBack<boost::mpl::_1, boost::mpl::_2, ENUM2ORDER0, ENUM2ORDER1>
	>::type VECTOR;
	typedef typename boost::mpl::if_<
		typename boost::mpl::less_equal<
			typename sum<VECTOR>::type,
			MAXORDER
		>::type,
		boost::mpl::insert<
			SET,
			VECTOR
		>,
		self<SET>
	>::type::type type;
};
template<typename SET, typename ENUM2ORDER, typename POS2ENUM2ORDER, typename MAXORDER>
struct multiplyOrder
{	typedef typename sum<ENUM2ORDER>::type SUM;
	typedef typename filterEnum2OrderSet<POS2ENUM2ORDER, boost::mpl::long_<MAXORDER::value - SUM::value> >::type SUBSET;
	typedef typename boost::mpl::accumulate<
		SUBSET,
		SET,
		multiplyOrder2<boost::mpl::_1, boost::mpl::_2, ENUM2ORDER, MAXORDER>
	>::type type;
};
template<typename _POS2ENUM2ORDER0, typename _POS2ENUM2ORDER1, typename _MAXORDER>
struct createTypeMultiplication<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER0, _MAXORDER> >, CTaylor<boost::mpl::pair<_POS2ENUM2ORDER1, _MAXORDER> > >
{	typedef typename boost::mpl::accumulate<
		_POS2ENUM2ORDER0,
		boost::mpl::set<>,
		multiplyOrder<boost::mpl::_1, boost::mpl::_2, _POS2ENUM2ORDER1, _MAXORDER>
	>::type SET;
#if 0
	typedef typename boost::mpl::accumulate<
		SET,
		boost::mpl::vector<>,
		boost::mpl::push_back<boost::mpl::_1, boost::mpl::_2>
	>::type VECTOR;
	typedef CTaylor<boost::mpl::pair<VECTOR, _MAXORDER> > type;
#else
	typedef CTaylor<boost::mpl::pair<SET, _MAXORDER> > type;
#endif
};
template<typename _POS2ENUM2ORDER0, typename _MAXORDER>
struct createTypeMultiplication<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER0, _MAXORDER> >, double>
{	typedef CTaylor<boost::mpl::pair<_POS2ENUM2ORDER0, _MAXORDER> > type;
};
template<typename _POS2ENUM2ORDER0, typename _MAXORDER>
struct createTypeMultiplication<double, CTaylor<boost::mpl::pair<_POS2ENUM2ORDER0, _MAXORDER> >>
{	typedef CTaylor<boost::mpl::pair<_POS2ENUM2ORDER0, _MAXORDER> > type;
};

template<typename STATE, typename ORDER, typename T0>
struct createTypeNonlinear1
{	typedef typename createTypeAdditionSubtraction<
		STATE,
		typename createTypePow<
			T0, 
			ORDER
		>::type
	>::type type;	
};
template<typename T0>
struct createTypeNonlinear
{	typedef typename boost::mpl::accumulate<
		typename boost::mpl::range_c<
			std::size_t,
			2,
			T0::MAXORDER::value+1
		>::type,
		T0,
		createTypeNonlinear1<boost::mpl::_1, boost::mpl::_2, T0>
	>::type type;
};

template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type exp(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[0] = std::exp(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	for (std::size_t i = 1; i < CRET::SIZE; ++i)
		s.m_ad[i] = s.m_ad[i-1]/i;
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type pow(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r, const double _d)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	double d = _d;
	s.m_ad[0] = std::pow(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value], d);
	for (std::size_t i = 1; i < CRET::SIZE; ++i)
	{	s.m_ad[i] = d*s.m_ad[i - 1]/_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]/i;
		d = d - 1;
	}
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type pow(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r0, const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r1)
{	return std::exp(_r1*std::log(_r0));
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type pow(const double _d0, const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r1)
{	return std::exp(_r1*std::log(_d0));
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type sqrt(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	double d = 0.5;
	s.m_ad[0] = std::sqrt(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	for (std::size_t i = 1; i < CRET::SIZE; ++i)
	{	s.m_ad[i] = s.m_ad[i - 1]/_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]/i*d;
		d = d - 1;
	}
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type abs(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	return std::sqrt(_r*_r);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type log(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[0] = std::log(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	s.m_ad[1] = 1.0/_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value];
	for (std::size_t i = 2; i < CRET::SIZE; ++i)
		s.m_ad[i] = -s.m_ad[i-1]*(i-1)*s.m_ad[1]/i;
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
static const double s_dLog10 = std::log(10.0);
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type log10(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	return std::log(_r)/s_dLog10;
}

template<typename _POS2ENUM2ORDER, typename _MAXORDER>
struct SIN
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET *const m_p;
	double *const m_pd;
	__forceinline SIN(CRET *const _p, double *const _pd)
		:m_p(_p),
		m_pd(_pd)
	{	*m_pd = 1;
	}
	template<typename T>
	__forceinline void operator()(const T &) const
	{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value> > >::type POS;
		*m_pd *= T::value;
		BOOST_MPL_ASSERT((
			typename boost::mpl::less<
				boost::mpl::long_<T::value>,
				boost::mpl::long_<CRET::SIZE>
			>::type));
		switch (T::value % 4)
		{	case 3:
				m_p->m_ad[POS::value] = -m_p->m_ad[boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type::value]/ *m_pd;
				break;
			case 2:
				m_p->m_ad[POS::value] = -m_p->m_ad[CRET::VALUEPOS::value]/ *m_pd;
				break;
			case 1:
				m_p->m_ad[POS::value] = m_p->m_ad[boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type::value]/ *m_pd;
				break;
			case 0:
				m_p->m_ad[POS::value] = m_p->m_ad[CRET::VALUEPOS::value]/ *m_pd;
				break;
		}
	}
};
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type sin(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::sin(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type POS1;
	s.m_ad[POS1::value] = std::cos(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(SIN<_POS2ENUM2ORDER, _MAXORDER>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
struct SINH_COSH
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET *const m_p;
	double *const m_pd;
	__forceinline SINH_COSH(CRET *const _p, double *const _pd)
		:m_p(_p),
		m_pd(_pd)
	{	*m_pd = 1;
	}
	template<typename T>
	__forceinline void operator()(const T &) const
	{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value> > >::type POS;
		*m_pd *= T::value;
		switch (T::value % 2)
		{	case 1:
				m_p->m_ad[POS::value] = m_p->m_ad[boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type::value]/ *m_pd;
				break;
			case 0:
				m_p->m_ad[POS::value] = m_p->m_ad[CRET::VALUEPOS::value]/ *m_pd;
				break;
		}
	}
};
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type sinh(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::sinh(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type POS1;
	s.m_ad[POS1::value] = std::cosh(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(SINH_COSH<_POS2ENUM2ORDER, _MAXORDER>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type cosh(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::cosh(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type POS1;
	s.m_ad[POS1::value] = std::sinh(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(SINH_COSH<_POS2ENUM2ORDER, _MAXORDER>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}

template<typename _POS2ENUM2ORDER, typename _MAXORDER>
struct COS
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET *const m_p;
	double *const m_pd;
	__forceinline COS(CRET *const _p, double *const _pd)
		:m_p(_p),
		//m_d(1.0),
		m_pd(_pd)
	{	*m_pd = 1;
	}
	template<typename T>
	__forceinline void operator()(const T &) const
	{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value> > >::type POS;
		typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type POS1;
		*m_pd *= T::value;
		switch (T::value % 4)
		{	case 3:
				m_p->m_ad[POS::value] = -m_p->m_ad[POS1::value]/ *m_pd;
				break;
			case 2:
				m_p->m_ad[POS::value] = -m_p->m_ad[CRET::VALUEPOS::value]/ *m_pd;
				break;
			case 1:
				m_p->m_ad[POS::value] = m_p->m_ad[POS1::value]/ *m_pd;
				break;
			case 0:
				m_p->m_ad[POS::value] = m_p->m_ad[CRET::VALUEPOS::value]/ *m_pd;
				break;
		}
	}
};
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type cos(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	double d;
	s.m_ad[CRET::VALUEPOS::value] = std::cos(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<1> > >::type POS1;
	s.m_ad[POS1::value] = -std::sin(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(COS<_POS2ENUM2ORDER, _MAXORDER>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename ORDER, typename EXP>
struct derive
{	typedef typename boost::mpl::if_<
		typename boost::mpl::greater<
			ORDER,
			boost::mpl::long_<0>
		>::type,
		derive<
			boost::mpl::long_<ORDER::value-1>, 
			typename EXP::template derivative<foelsche::cte::x<boost::mpl::long_<0> > >::type
		>,
		self<EXP>
	>::type::type type;
};
template<typename ORDER, typename CRET>
struct DERVALUE
{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<ORDER::value> > >::type POS;
	__forceinline double operator()(const std::pair<double, CRET> &_r) const
	{	return _r.second.m_ad[POS::value];
	}
	template<typename IX>
	struct derivative
	{	typedef DERVALUE<boost::mpl::long_<ORDER::value+1>, CRET> type;
	};
	typedef DERVALUE type;
	inline friend std::ostream &operator<<(std::ostream &_r, const DERVALUE &)
	{	return _r << "value[" << ORDER::value << "]";
	}
};
template<typename CRET>
struct DERVALUE<boost::mpl::long_<0>, CRET>
{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<> >::type POS;
	__forceinline double operator()(const std::pair<double, CRET> &_r) const
	{	return _r.second.m_ad[POS::value];
	}
	template<typename IX>
	struct derivative
	{	typedef DERVALUE<boost::mpl::long_<1>, CRET> type;
	};
	typedef DERVALUE type;
	inline friend std::ostream &operator<<(std::ostream &_r, const DERVALUE<boost::mpl::long_<0>, CRET> &)
	{	return _r << "value[0]";
	}
};
template<typename CRET, typename ORDER, template<typename X> class FUN>
struct createAndReplace;

template<typename CRET, long I, template<typename X> class FUN>
struct createAndReplace<CRET, boost::mpl::long_<I>, FUN>
{	typedef typename createAndReplace<CRET, boost::mpl::long_<I-1>, FUN>::type PREV;
	typedef typename PREV::template derivative<boost::mpl::long_<0> >::type DER;
	typedef typename foelsche::cte::substitute<
		typename foelsche::cte::simplify<DER, 0>::type, 
		PREV, 
		DERVALUE<
			boost::mpl::long_<I-1>, 
			CRET
		>,
		0
	>::type type2;
	typedef typename foelsche::cte::simplify<type2, 0>::type type;
	//typedef typename foelsche::cte::simplify<DER>::type type;
};
template<typename CRET, template<typename X> class FUN>
struct createAndReplace<CRET, boost::mpl::long_<0>, FUN>
{	typedef FUN<foelsche::cte::x<boost::mpl::long_<0> > > type;
};
template<typename _POS2ENUM2ORDER, typename _MAXORDER, template<typename X> class FUN>
struct SUBSTITUTED
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET *const m_p;
	const double m_dX;
	__forceinline SUBSTITUTED(CRET *const _p, const double _dX)
		:m_p(_p),
		m_dX(_dX)
	{
	}
	template<typename T>
	__forceinline void operator()(const T &) const
	{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value> > >::type POS;
		typedef typename createAndReplace<CRET, boost::mpl::long_<T::value>, FUN>::type REPLACED;
		m_p->m_ad[POS::value] = REPLACED()(std::make_pair(m_dX, *m_p));
	}
};
template<typename CRET>
struct convert2taylor
{	CRET *const m_p;
	double *const m_pd;
	__forceinline convert2taylor(CRET *const _p, double *const _pd)
		:m_p(_p),
		m_pd(_pd)
	{	*m_pd = 1;
	}
	template<typename T>
	__forceinline void operator()(const T &) const
	{	typedef typename boost::mpl::at<typename CRET::ORDER2POS, boost::mpl::vector<boost::mpl::long_<T::value> > >::type POS;
		*m_pd *= T::value;
		m_p->m_ad[POS::value] /= *m_pd;
	}
};
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type tan(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::tan(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 1, CRET::SIZE>::type>(SUBSTITUTED<_POS2ENUM2ORDER, _MAXORDER, foelsche::cte::tan_>(&s, _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]));
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(convert2taylor<CRET>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type tanh(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::tanh(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 1, CRET::SIZE>::type>(SUBSTITUTED<_POS2ENUM2ORDER, _MAXORDER, foelsche::cte::tanh_>(&s, _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]));
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(convert2taylor<CRET>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type asin(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::asin(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 1, CRET::SIZE>::type>(SUBSTITUTED<_POS2ENUM2ORDER, _MAXORDER, foelsche::cte::asin_>(&s, _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]));
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(convert2taylor<CRET>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}
template<typename _POS2ENUM2ORDER, typename _MAXORDER>
__forceinline typename createTypeNonlinear<CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > >::type acos(const CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> > &_r)
{	typedef typename createSingleVariableCTaylor<_MAXORDER>::type CRET;
	CRET s;
	s.m_ad[CRET::VALUEPOS::value] = std::acos(_r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
	boost::mpl::for_each<
		typename boost::mpl::range_c<
			std::size_t,
			1,
			CRET::SIZE
		>::type
	>(SUBSTITUTED<_POS2ENUM2ORDER, _MAXORDER, foelsche::cte::acos_>(&s, _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]));
	double d;
	boost::mpl::for_each<typename boost::mpl::range_c<std::size_t, 2, CRET::SIZE>::type>(convert2taylor<CRET>(&s, &d));
	s.check();
	_r.check();
	return s.apply(_r - _r.m_ad[CTaylor<boost::mpl::pair<_POS2ENUM2ORDER, _MAXORDER> >::VALUEPOS::value]);
}

template<typename T>
__forceinline decltype(T()*T()) sqr(const T &_r)
{	return _r*_r;
}

template<typename SIZE>
struct createZeroVector
{	typedef typename boost::mpl::accumulate<
		typename boost::mpl::range_c<
			std::size_t,
			0,
			SIZE::value
		>::type,
		boost::mpl::vector<>,
		boost::mpl::push_back<
			boost::mpl::_1,
			boost::mpl::long_<0>
		>
	>::type type;
};
template<typename ENUM, typename MAXORDER>
struct createCTaylor
{	typedef typename boost::mpl::push_back<
		typename createZeroVector<ENUM>::type,
		boost::mpl::long_<1>
	>::type ENUM2ORDER;
	typedef boost::mpl::vector<
		boost::mpl::vector<>,
		ENUM2ORDER
	> POS2ENUM2ORDER;
	typedef CTaylor<boost::mpl::pair<POS2ENUM2ORDER, MAXORDER> > type;
};
#undef max
template<typename A, typename B>
__forceinline decltype(A() + B()) max(const A &_rA, const B &_rB)
{	if (_rA > _rB)
		return _rA;
	else
		return _rB;
}
#undef min
template<typename A, typename B>
__forceinline decltype(A() + B()) min(const A &_rA, const B &_rB)
{	if (_rA < _rB)
		return _rA;
	else
		return _rB;
}

struct EXP
{ 	template<typename ARGS> 
	struct sig
	{	 typedef typename std::createTypeNonlinear<
			typename boost::remove_const<
				typename boost::tuples::element<1, ARGS>::type
			>::type
		>::type type;
	};
	template<typename T> 
	__forceinline typename std::createTypeNonlinear<T>::type operator()(const T &arg) const 
	{	return std::exp(arg); 
	} 
}; 
struct LOG
{ 	template<typename ARGS> 
	struct sig
	{	 typedef typename std::createTypeNonlinear<
			typename boost::remove_const<
				typename boost::tuples::element<1, ARGS>::type
			>::type
		>::type type;
	};
	template<typename T> 
	__forceinline typename std::createTypeNonlinear<T>::type operator()(const T &arg) const 
	{	return std::log(arg); 
	} 
}; 
struct SQRT
{ 	template<typename ARGS> 
	struct sig
	{	 typedef typename std::createTypeNonlinear<
			typename boost::remove_const<
				typename boost::tuples::element<1, ARGS>::type
			>::type
		>::type type;
	};
	template<typename T>
	__forceinline typename std::createTypeNonlinear<T>::type operator()(const T &arg) const 
	{	return std::sqrt(arg); 
	} 
}; 
struct SQR
{ 	template<typename ARGS> 
	struct sig
	{	 typedef typename std::createTypeMultiplication<
			typename boost::remove_const<
				typename boost::tuples::element<1, ARGS>::type
			>::type,
			typename boost::remove_const<
				typename boost::tuples::element<1, ARGS>::type
			>::type
		>::type type;
	};
	template<typename T>
	__forceinline typename std::createTypeMultiplication<T, T>::type operator()(const T &arg) const 
	{	return arg*arg; 
	} 
}; 


struct FIRST
{ 	template<typename ARGS> 
	struct sig
	{	 typedef typename boost::remove_const<
			typename boost::tuples::element<1, ARGS>::type
		>::type::first_type type;
	};
	template<typename T0, typename T1>
	__forceinline T0 operator()(const std::pair<T0, T1> &arg) const 
	{	return arg.first; 
	} 
}; 
struct SECOND
{ 	template<typename ARGS> 
	struct sig
	{	 typedef typename boost::remove_const<
			typename boost::tuples::element<1, ARGS>::type
		>::type::second_type type;
	};
	template<typename T0, typename T1>
	__forceinline T1 operator()(const std::pair<T0, T1> &arg) const 
	{	return arg.second; 
	} 
}; 


template<unsigned int I>
struct GET;


template<>
struct GET<0>
{ 	template<typename ARGS> 
	struct sig
	{	typedef typename boost::remove_const<
			typename boost::tuples::element<1, ARGS>::type
		>::type::first_type type;
	};
	template<typename T0, typename T1>
	__forceinline T0 operator()(const std::pair<T0, T1>&arg) const 
	{	return arg.first; 
	} 
}; 


template<unsigned int I>
struct GET
{	template<typename ARGS> 
	struct sig
	{	typedef typename boost::remove_const<
			typename boost::tuples::element<1, ARGS>::type
		>::type::second_type second;
		typedef typename GET<I-1>::template sig<boost::tuple<second> >::type type; 	
	};
	template<typename T0, typename T1>
	__forceinline typename GET<I-1>::template sig<boost::tuple<T1> >::type operator()(const std::pair<T0, T1> &arg) const 
	{	return GET<I-1>()(arg.second); 
	}
};

template<typename ENUM2ORDER>
struct copy_enum
{	std::vector<std::size_t> *const m_pEnum2Order;
	copy_enum(
		std::vector<std::size_t> *const _pEnum2Order)
		:m_pEnum2Order(_pEnum2Order)
	{
	}
	template<typename ORDER>
	void operator()(const ORDER &) const
	{	m_pEnum2Order->push_back(ORDER::value);
	}		
};
}
template<typename A0, typename A1, typename B0, typename B1>
typename std::createTypeAdditionSubtraction<std::pair<A0, A1>, std::pair<B0, B1> >::type operator+(const std::pair<A0, A1>&_r0, const std::pair<B0, B1>&_r1)// -> decltype(std::make_pair(_r0.first + _r1.first, _r0.second + _r1.second))
{	return std::make_pair(_r0.first + _r1.first, _r0.second + _r1.second);
}
namespace boost
{
namespace lambda
{
//using namespace foelsche::cder;


template<typename A, typename B>
struct plain_return_type_2<
	arithmetic_action<plus_action>,
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B>
	>::type type;
};


template<typename A>
struct plain_return_type_2<
	arithmetic_action<plus_action>,
	double,
	std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};


template<typename A>
struct plain_return_type_2<
	arithmetic_action<plus_action>,
	std::CTaylor<A>,
	double
>
{	typedef std::CTaylor<A> type;
};


template<typename A, typename B>
struct plain_return_type_2<
	arithmetic_action<minus_action>,
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};




template<typename A>
struct plain_return_type_2<
	arithmetic_action<minus_action>,
	double,
	std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};


template<typename A>
struct plain_return_type_2<
	arithmetic_action<minus_action>,
	std::CTaylor<A>,
	double
>
{	typedef std::CTaylor<A> type;
};


template<typename A, typename B>
struct plain_return_type_2<
	arithmetic_action<multiply_action>,
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeMultiplication<
		std::CTaylor<A>, 
		std::CTaylor<B>
	>::type type;
};
template<typename A>
struct plain_return_type_2<
	arithmetic_action<multiply_action>,
	std::CTaylor<A>,
	double
>
{	typedef std::CTaylor<A> type;
};


template<typename A>
struct plain_return_type_2<
	arithmetic_action<multiply_action>,
	double,
	std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};


template<typename A, typename B>
struct plain_return_type_2<
	arithmetic_action<divide_action>,
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeMultiplication<
		std::CTaylor<A>, 
		typename std::createTypeNonlinear<
			std::CTaylor<B>
		>::type
	>::type type;
};
template<typename A>
struct plain_return_type_2<
	arithmetic_action<divide_action>,
	std::CTaylor<A>,
	double
>
{	typedef std::CTaylor<A> type;
};
template<typename A>
struct plain_return_type_2<
	arithmetic_action<divide_action>,
	double,
	std::CTaylor<A>
>
{	typedef typename std::createTypeNonlinear<
		std::CTaylor<A>
	>::type type;
};
template<typename ACTION, typename A>
struct plain_return_type_1<
	unary_arithmetic_action<ACTION>, 
	std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};

template<typename ACTION, typename A, typename B>
struct plain_return_type_2<
	relational_action<ACTION>, 
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef bool type;
};
template<typename ACTION, typename A>
struct plain_return_type_2<
	relational_action<ACTION>, 
	std::CTaylor<A>,
	double
>
{	typedef bool type;
};
template<typename ACTION, typename A>
struct plain_return_type_2<
	relational_action<ACTION>, 
	double,
	std::CTaylor<A>
>
{	typedef bool type;
};
template<typename A, typename B>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	double,
	std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	std::CTaylor<A>,
	double
>
{	typedef std::CTaylor<A> type;
};


template<typename A, typename B>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	const std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	const double,
	std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	const std::CTaylor<A>,
	double
>
{	typedef std::CTaylor<A> type;
};


template<typename A, typename B>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	std::CTaylor<A>,
	const std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	double,
	const std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	std::CTaylor<A>,
	const double
>
{	typedef std::CTaylor<A> type;
};




template<typename A, typename B>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	const std::CTaylor<A>,
	const std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	const double,
	const std::CTaylor<A>
>
{	typedef std::CTaylor<A> type;
};
template<typename A>
struct return_type_2<
	other_action<ifthenelsereturn_action>, 
	const std::CTaylor<A>,
	const double
>
{	typedef std::CTaylor<A> type;
};
namespace detail
{

template<typename A, typename B>
struct return_type_2_ifthenelsereturn<
	1,
	true,
	true,
	false,
	std::CTaylor<A>,
	std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A, typename B>
struct return_type_2_ifthenelsereturn<
	1,
	true,
	true,
	false,
	std::CTaylor<A>,
	const std::CTaylor<B>&
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A, typename B>
struct return_type_2_ifthenelsereturn<
	1,
	true,
	true,
	false,
	const std::CTaylor<A>&,
	const std::CTaylor<B>&
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};
template<typename A, typename B>
struct return_type_2_ifthenelsereturn<
	1,
	true,
	true,
	false,
	const std::CTaylor<A>&,
	std::CTaylor<B>
>
{	typedef typename std::createTypeAdditionSubtraction<
		std::CTaylor<A>, 
		std::CTaylor<B> 
	>::type type;
};

}
}
}
#endif //! cder_CTaylor_h_included
